#!/usr/bin/env python
# encoding: utf-8
"""
net.py

Created by Morgan Quirk on 2007-09-20.
"""

from socket import *
import entity

class UDPConn:
    buffer = 1024
    
    def __init__(self, addr, port):
        self.addr = addr
        self.port = port
        
        self.sock = socket(AF_INET, SOCK_DGRAM)
        self.sock.bind(("127.0.0.1",port))
        self.sock.setblocking(0)
        
    def send_data(self, datalist, addr, port):
        for data in datalist:
            print (data, (addr,port))
            self.sock.sendto(data, (addr, port))
            
    def recv_data(self):
        datalist = []
        data, addr = None, None
        try:
            data, addr = self.sock.recvfrom(self.buffer)
            while data:
                datalist.append((data, addr))
                try:
                    data, addr = self.sock.recvfrom(self.buffer)
                except:
                    data, addr = None, None
        except:
            pass
        return datalist
        
    def update(self, datalist, addr, port):
        self.senddata(datalist, addr, port)
        return self.recvdata()

object_dict = {
                "test1":entity.Entity_Test1,
                "test2":entity.Entity_Test2,
              }

action_list = [
               "join",
               "move_up",
               "move_down",
               "move_left",
               "move_right",
               "create_ent",
               "update_ent",
               ]
ASCII_offset = 60
               
action_to_packet = {}
packet_to_action = {}



for count in range(len(action_list)):
    action_to_packet[action_list[count]] = chr(count+ASCII_offset)
    packet_to_action[chr(count+ASCII_offset)] = action_list[count]

class NetClient:
    def __init__(self, ent_manager, server, port):
        self.client_func = {
               "create_ent":self.on_construct_ent,
               "update_ent":self.on_update_ent,
        }
        self.server = server
        self.port = port
        self.conn = NetConn(server, port)
        
        self.ent_dict={}
        self.ent_manager=ent_manager
        
        self.to_send=[]     #Stores everything that will be sent this tick
        
    def send_action(self, action, *args):
        sendstring = action_to_packet[action]+":"
        if args:
            for arg in args:
                sendstring = sendstring+str(arg)+","
        sendstring=sendstring[:-1]
        self.to_send.append(sendstring)
        
    def update(self):
        self.conn.send_data(self.to_send, self.server, self.port-1)
        self.to_send=[]
        
        data=self.conn.recv_data()        
        for pack in data:
            print pack            
            packdata, addr = pack
            self.client_func[packet_to_action[packdata.split(":")[0]]](packdata.split(":")[1].split(","))
        
    def on_construct_ent(self, args):
        print args
        net_id=args[0]
        object_name=args[1]
        create_args=args[2:]
        new_ent=object_dict[object_name](*create_args)
        new_ent.net_id=net_id
        self.ent_manager.add_entity(new_ent)
        self.ent_dict[net_id]=new_ent
        
    def on_update_ent(self, args):
        net_id=args[0]
        self.ent_dict[net_id].x=args[1]
        self.ent_dict[net_id].y=args[2]
        self.ent_dict[net_id].xv=args[3]
        self.ent_dict[net_id].yv=args[4]        
        self.ent_dict[net_id].angle=args[5]
        
        
class NetServer:
    def __init__(self, ent_manager, port):
        self.server_func = {
            "join":self.on_player_join
        }
        
        self.port = port
        self.conn = NetConn("127.0.0.1", self.port)
        
        self.ent_manager = ent_manager
        self.ent_dict={}
        self.clients=[]
        self.to_send=[] #list of lists of data
        
    def send_action(self, cnum, action, *args):
        sendstring = action_to_packet[action]+":"
        if args:
            for arg in args:
                sendstring = sendstring+str(arg)+","
        sendstring=sendstring[:-1]
        if cnum is not None:
            self.to_send[cnum].append(sendstring)
        else:
            for c in range(len(self.clients)):
                self.to_send[c].append(sendstring)
            
    
    def update(self):
        for i in range(len(self.clients)):
            self.conn.send_data(self.to_send[i], self.clients[i], self.port+1)
        self.to_send=[]
        for i in range(len(self.clients)):
            self.to_send.append([])
        data=self.conn.recv_data()
        for pack in data:
            print pack
            packdata, addr = pack
            self.server_func[packet_to_action[packdata.split(":")[0]]](addr[0], packdata.split(","))
            
    def make_net_ent(self, object_name, args):
        new_ent=object_dict[object_name](*args)
        self.ent_manager.add_entity(new_ent)
        net_id = len(self.ent_dict)+1
        new_ent.net_id=net_id
        
        self.ent_dict[net_id]=new_ent
        self.send_action(None, "create_ent", net_id, object_name, *args)
        
    def update_ents(self):
        for net_id in self.ent_dict:
            ent=self.ent_dict[net_id]
            self.send_action(None, "update_ent", net_id, ent.x, ent.y, ent.xv, ent.yv, ent.angle)
            
    def on_player_join(self, addr, args):
        print "Player "+args[0]+" joined the game."
        self.clients.append(addr)
        self.to_send.append([])
        self.make_net_ent("test1", (120,100, 2, 1, 0))
        